Amazon IVSのマニフェストファイルを眺めてみた
はじめに
清水です。簡単にセットアップでき、しかも超低遅延な配信ができるAWSのライブストリーミングソリューションAmazon Interactive Video Service (Amazon IVS)、本エントリではあえて?動画自体ではなくマニフェストファイル(拡張子.m3u8のファイル)に焦点を当て、その中身やヘッダ情報などからわかることをまとめてみました。
なお本エントリでは、Amazon IVSのChannelはオレゴンリージョンに作成し、注釈などない限りマネジメントコンソールからデフォルト設定で作成したChannelで確認した結果となります。
マニフェストファイルを眺めてみる
トップレベルマニフェストファイルのヘッダ情報
まずはIVSのChannelで払い出されるPlayback URL、つまりトップレベルのマニフェストファイルから確認していきます。マニフェストファイルの内容を確認する前に、レスポンスヘッダの情報をみてみましょう。curl
コマンドに-I
オプションをつけて実行します。
% curl -I https://XXXXXXXXXXXX.us-west-2.playback.live-video.net/api/video/v1/us-west-2.123456789012.channel.XXXXXXXXsS0f.m3u8 HTTP/1.1 200 OK Server: nginx/1.14.1 Date: Tue, 29 Sep 2020 10:46:36 GMT Content-Type: application/vnd.apple.mpegurl Content-Length: 7828 Access-Control-Allow-Origin: * Cache-Control: no-cache,no-store
レスポンスヘッダのうち、Serverヘッダにはnginx/1.14.1
の記載があります。Amazon IVSの中ではNginxが動いている?のかもしれません。(Serverヘッダ情報のみでの推測ですが。そして仮にNginxが使われていても、いろいろカスタマイズなどはしているのだろうなぁと思います。)ちなみに、AWS Elemental MediaPackageでもNginxのServerヘッダが返ってきたことがあります。(例えばこちらのエントリなどから確認ができます。)
CORS設定の際に必要なAccess-Control-Allow-Originヘッダも気になりますが、こちらは後述します。続いてマニフェストファイルの中身をみてみましょう。
トップレベルマニフェストの中身
curl
コマンドにPlayback URLを指定して、そのレスポンス(マニフェストファイルの中身)を確認してみます。するとちょっとギョッとするほどの文字列が現れますね。各ビットレートへのマニフェストファイルのファイル名が800文字超のランダムな文字列で構成されていて、整理すると以下のようになります。
% curl https://XXXXXXXXXXXX.us-west-2.playback.live-video.net/api/video/v1/us-west-2.123456789012.channel.XXXXXXXXsS0f.m3u8 #EXTM3U #EXT-X-SESSION-DATA:DATA-ID="NODE",VALUE="video-edge-755d74.tyo01" #EXT-X-SESSION-DATA:DATA-ID="MANIFEST-NODE-TYPE",VALUE="weaver_cluster" #EXT-X-SESSION-DATA:DATA-ID="MANIFEST-NODE",VALUE="video-weaver.tyo01" #EXT-X-SESSION-DATA:DATA-ID="SUPPRESS",VALUE="true" #EXT-X-SESSION-DATA:DATA-ID="SERVER-TIME",VALUE="1601376547.49" #EXT-X-SESSION-DATA:DATA-ID="TRANSCODESTACK",VALUE="2017TranscodeQS_V2" #EXT-X-SESSION-DATA:DATA-ID="USER-IP",VALUE="[アクセス元IPv4アドレス]" #EXT-X-SESSION-DATA:DATA-ID="SERVING-ID",VALUE="[32文字のランダムな文字列]" #EXT-X-SESSION-DATA:DATA-ID="CLUSTER",VALUE="tyo01" #EXT-X-SESSION-DATA:DATA-ID="ABS",VALUE="false" #EXT-X-SESSION-DATA:DATA-ID="VIDEO-SESSION-ID",VALUE="[19桁の数字]" #EXT-X-SESSION-DATA:DATA-ID="BROADCAST-ID",VALUE="[11桁の数字]" #EXT-X-SESSION-DATA:DATA-ID="STREAM-TIME",VALUE="195.485890" #EXT-X-SESSION-DATA:DATA-ID="FUTURE",VALUE="true" #EXT-X-SESSION-DATA:DATA-ID="MANIFEST-CLUSTER",VALUE="tyo01" #EXT-X-SESSION-DATA:DATA-ID="ORIGIN",VALUE="sjc02" #EXT-X-SESSION-DATA:DATA-ID="C",VALUE="[1000文字超のランダムな文字列]" #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="chunked",NAME="1080p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=5550839,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2",VIDEO="chunked",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列1].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="720p30",NAME="720p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=2348396,RESOLUTION=1280x720,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="720p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列2].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="480p30",NAME="480p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=1403396,RESOLUTION=852x480,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="480p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列3].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="360p30",NAME="360p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=630000,RESOLUTION=640x360,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="360p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列4].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="160p30",NAME="160p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=230000,RESOLUTION=284x160,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="160p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列5].m3u8
まず#EXT-X-SESSION-DATA
ではじまる情報がたくさんありますね。17個。HLSなどの仕様書と照らし合わせるとおもしろいかもしれません。(私はきちんと仕様書を読んだことはなく、詳細はわからないのですが……)読み取れる情報を確認していきましょう。
DATA-ID="USER-IP"
という項目があり、実際にアクセスもとのIPv4アドレスが記載されています。そのほかにもIDとなりそうな情報があり、またヘッダ情報でCache-Control: no-cache,no-store
があることから、トップレベルマニフェストファイルについてはクライアントからのアクセスごと動的に生成しているのかな、と推測しています。
IVSのABR設定
続いて後半、#EXT-X-STREAM-INF
と#EXT-X-MEDIA
が並ぶ部分に進んでいきましょう。こちらはAmazon IVSのAdaptive Bit Rate (ABR)についての情報が確認できますね。代表的な項目だけ抜き出してみました。
NAME | BANDWIDTH | RESOLUTION | FRAME-RATE |
---|---|---|---|
1080p | 5,550,839 | 1920x1080 | 30.000 |
720p | 2,348,396 | 1280x720 | 30.000 |
480p | 1,403,396 | 852x480 | 30.000 |
360p | 630,000 | 640x360 | 30.000 |
160p | 230,000 | 284x160 | 30.000 |
今回は1920x1080で映像を打ち上げています。ビットレートなどStreaming Softwareの設定や映像に起因する項目もあるかと思いますが、おそらく(1) 1920x1080で映像を打ち上げている、(2) Standard Channelである、という条件であれば上記のように5つのABRで構成されるのかなと思います。Amazon IVSの公式ページ、よくある質問に記載されている出力ストリームの種類にも一致しますね。 *1また最も小さい解像度で160p、230kbpsとネットワークが不安定な場所などでも、視聴ができそうです。
縦長Portraitなライブ配信でも確認してみました。1080x1920のフル解像度の映像を打ち上げています。
#EXTM3U #EXT-X-SESSION-DATA:DATA-ID="NODE",VALUE="video-edge-5a748c.tyo01" #EXT-X-SESSION-DATA:DATA-ID="MANIFEST-NODE-TYPE",VALUE="weaver_cluster" #EXT-X-SESSION-DATA:DATA-ID="MANIFEST-NODE",VALUE="video-weaver.tyo01" #EXT-X-SESSION-DATA:DATA-ID="SUPPRESS",VALUE="true" #EXT-X-SESSION-DATA:DATA-ID="SERVER-TIME",VALUE="1601378231.04" #EXT-X-SESSION-DATA:DATA-ID="TRANSCODESTACK",VALUE="2017TranscodeQS_V2" #EXT-X-SESSION-DATA:DATA-ID="USER-IP",VALUE="[アクセス元IPv4アドレス]" #EXT-X-SESSION-DATA:DATA-ID="SERVING-ID",VALUE="[32文字のランダムな文字列]" #EXT-X-SESSION-DATA:DATA-ID="CLUSTER",VALUE="tyo01" #EXT-X-SESSION-DATA:DATA-ID="ABS",VALUE="false" #EXT-X-SESSION-DATA:DATA-ID="VIDEO-SESSION-ID",VALUE="[19桁の数字]" #EXT-X-SESSION-DATA:DATA-ID="BROADCAST-ID",VALUE="[11桁の数字]" #EXT-X-SESSION-DATA:DATA-ID="STREAM-TIME",VALUE="64.042630" #EXT-X-SESSION-DATA:DATA-ID="FUTURE",VALUE="true" #EXT-X-SESSION-DATA:DATA-ID="MANIFEST-CLUSTER",VALUE="tyo01" #EXT-X-SESSION-DATA:DATA-ID="ORIGIN",VALUE="sjc02" #EXT-X-SESSION-DATA:DATA-ID="C",VALUE="[100-文字超のランダムな文字列]" #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="chunked",NAME="1920p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=9426231,RESOLUTION=1080x1920,CODECS="avc1.420028,mp4a.40.2",VIDEO="chunked",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列1].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="720p30",NAME="720p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=2312689,RESOLUTION=404x720,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="720p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列2].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="480p30",NAME="480p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=1367689,RESOLUTION=268x480,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="480p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列3].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="360p30",NAME="360p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=630000,RESOLUTION=200x360,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="360p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列4].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="160p30",NAME="160p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=230000,RESOLUTION=88x160,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="160p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列5].m3u8
こちらも#EXT-X-STREAM-INF
と#EXT-X-MEDIA
が並ぶ部分から、ABRの情報を抜き出してみました。
NAME | BANDWIDTH | RESOLUTION | FRAME-RATE |
---|---|---|---|
1920p | 9,426,231 | 1080x1920 | 30.000 |
720p | 2,312,689 | 404x720 | 30.000 |
480p | 1,367,689 | 268x480 | 30.000 |
360p | 630,000 | 200x360 | 30.000 |
160p | 230,000 | 88x160 | 30.000 |
最もビットレート、解像度がよいものについては、1080x1920とフルHDの縦長Portrait状態と言えます。それ以外の解像度については、1280x720などではなく、横長Landscapeの垂直解像度、720や480などに合わせて水平解像度が決まっている点が興味深いですね。
ABRのマニフェストファイルの確認
ABRで一番ビットレート、解像度が高いものの、m3u8ファイルを参照してみます。まずはレスポンスヘッダです。
% curl -I https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列1].m3u8 HTTP/1.1 200 OK Access-Control-Allow-Origin: * Cache-Control: no-cache, no-store, private Content-Type: application/vnd.apple.mpegurl Vary: Accept-Encoding Date: Wed, 30 Sep 2020 03:42:14 GMT
CORS設定用のAccess-Control-Allow-Originヘッダや、Cache-Controlヘッダでno-cache, no-store, private
としていることなどが確認できますね。
続いてファイルの中身です。こちらもギョッとするほどの文字列が現れますが、整理すると以下のようになります。
#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:6 #EXT-X-MEDIA-SEQUENCE:54 #EXT-X-NET-LIVE-VIDEO-ELAPSED-SECS:107.995 #EXT-X-NET-LIVE-VIDEO-TOTAL-SECS:141.994 #EXT-X-DATERANGE:ID="source-1601437303",CLASS="live-video-net-stream-source",START-DATE="2020-09-30T03:41:43.386Z",END-ON-NEXT=YES,X-NET-LIVE-VIDEO-STREAM-SOURCE="live" #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:23.384Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列1].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:25.384Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列2].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:27.384Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列3].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:29.384Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列4].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:31.384Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列5].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:33.384Z #EXTINF:1.999,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列6].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:35.383Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列7].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:37.383Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列8].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:39.383Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列9].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:41.383Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列10].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:43.383Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列11].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:45.383Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列12].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:47.383Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列13].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:49.383Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列14].ts #EXT-X-PROGRAM-DATE-TIME:2020-09-30T03:42:51.383Z #EXTINF:2.000,live https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列15].ts #EXT-X-PREFETCH:https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列16].ts #EXT-X-PREFETCH:https://video-edge-7568a4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列17].ts
興味深いのは#EXT-X-PREFETCH
が使われている点でしょうか。ざっと調べてみた限り、おそらくLow-latency HLS(LHLS)に使用されるヘッダかと思われます。(FFMPEG 4.1でLHLSを有効にするには?)
またセグメントファイル(tsファイル)の参照先のDNS名についても注目してみましょう。ideo-edge-7568a4.tyo01.hls.live-video.net
となっています。Playback URLで示されているトップレベルマニフェストのDNS名、そしてそこから続くマニフェストファイル、セグメントファイル、それぞれで異なるDNS名からの配信となりますね。このDNS名については後ほどもう少し詳しく取り上げます。
Playback URLのCORS設定
Access-Control-Allow-Originヘッダ、CORS設定まわりについて確認してみましょう。おおまかですが、Access-Control-Allow-Originヘッダに記載がないドメインにAmazon IVS Playerを配置してもブラウザ側のJavaScriptの動作でエラーとなってしまい、正常にライブ動画が再生できない、となるかと思います。さてトップレベルマニフェストファイルのレスポンスヘッダでは、Access-Control-Allow-Origin: *
となっていました。これは対象のドメインは限定しない(どのドメインでもよい)となります。そのため例えば、AWSマネジメントコンソール上でも再生が可能になっている状態かと思います。
このようにIVSのトップレベルマニフェストファイルでは、デフォルトの状態でCORS設定についてはすべてのドメインを許可している状態です。これだと逆に言えば、Amazon IVSのPlayback URLが入手できれば、他の第三者が自分のWebページにライブ動画を埋め込んでしまえる状態である、ともいえます。この再生許可ドメインを限定するには、Amazon IVSのPrivate Channel機能が利用できます。Private Channel再生時のtoken(JWT)作成時、payloadに以下のように再生を許可したいドメインを指定しましょう。
{ "aws:channel-arn": <channel_arn>, "aws:access-control-allow-origin": "https://再生を許可したいドメイン", "exp": <unix timestamp> }
実際にPython環境でJWTを作成、Privateに設定しているIVS Channelで確認してみます。JWT作成方法はこちらのエントリをご参照ください。今回は以下のようにpayloadを指定しました。
>>> payload = { ... "aws:channel-arn": "arn:aws:ivs:us-west-2:123456789012:channel/XXXXXXXXXXXX", ... "aws:access-control-allow-origin": "https://my-s3-bucket.s3-ap-northeast-1.amazonaws.com", ... "exp": int(expires.timestamp()) ... }
payloadを指定してJWTを生成します。(encoded_jwtの中身、`で囲まれた部分になります。)
>>> encoded_jwt = jwt.encode(payload, secret, algorithm='ES384') >>> encoded_jwt b'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXImV4cCI6MTYwMTcwNTY0M30.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
このJWTでトップレベルマニフェストにアクセスしてみましょう。と言いつつ、まずは試しにPrivate ChannelのPlayback URLに対して、tokenなしでアクセスしてみます。
% curl -I https://XXXXXXXXXXXX.us-west-2.playback.live-video.net/api/video/v1/us-west-2.123456789012.channel.XXXXXXXXlctv.m3u8 HTTP/1.1 403 Forbidden Server: nginx/1.14.1 Date: Wed, 30 Sep 2020 06:24:07 GMT Content-Type: application/json Content-Length: 187 Access-Control-Allow-Origin: * Cache-Control: no-cache,no-store
レスポンスヘッダではステータスコード403
が返っていることが分かりますね。レスポンスの中身もみてみましょう。
% curl https://XXXXXXXXXXXX.us-west-2.playback.live-video.net/api/video/v1/us-west-2.123456789012.channel.XXXXXXXXlctv.m3u8 [{"url":"/api/video/v1/us-west-2.123456789012.channel.XXXXXXXXlctv.m3u8","error":"token contains an invalid number of segments","error_code":"invalid_playback_auth_token","type":"error"}]
エラー内容についての記載があります。これはデバッグなどの際に活用できそうですね。
続いて本題、tokenを付与してアクセスしてみましょう。まずはリクエストヘッダです。
% curl -I "https://XXXXXXXXXXXX.us-west-2.playback.live-video.net/api/video/v1/us-west-2.123456789012.channel.XXXXXXXXlctv.m3u8?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXImV4cCI6MTYwMTcwNTY0M30.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" HTTP/1.1 200 OK Server: nginx/1.14.1 Date: Wed, 30 Sep 2020 06:24:40 GMT Content-Type: application/vnd.apple.mpegurl Content-Length: 7814 Access-Control-Allow-Origin: https://my-s3-bucket.s3-ap-northeast-1.amazonaws.com Cache-Control: no-cache,no-store
Access-Control-Allow-Originヘッダでドメインが指定されていることがわかりますね!Private Channelということでアクセスにtokenが必要であることに加え、Access-Control-Allow-Originヘッダでもアクセス元ドメインを限定できていることがわかります。
このトップレベルマニフェストの中身も見てみましょう。こちらはPrivateでないChannelとあまり大差ないように見受けられます。
#EXTM3U #EXT-X-SESSION-DATA:DATA-ID="NODE",VALUE="video-edge-5cbaa4.tyo01" #EXT-X-SESSION-DATA:DATA-ID="MANIFEST-NODE-TYPE",VALUE="weaver_cluster" #EXT-X-SESSION-DATA:DATA-ID="MANIFEST-NODE",VALUE="video-weaver.tyo01" #EXT-X-SESSION-DATA:DATA-ID="SUPPRESS",VALUE="true" #EXT-X-SESSION-DATA:DATA-ID="SERVER-TIME",VALUE="1601447111.68" #EXT-X-SESSION-DATA:DATA-ID="TRANSCODESTACK",VALUE="2017TranscodeQS_V2" #EXT-X-SESSION-DATA:DATA-ID="USER-IP",VALUE="[アクセス元IPv4アドレス]" #EXT-X-SESSION-DATA:DATA-ID="SERVING-ID",VALUE="[32文字のランダムな文字列]" #EXT-X-SESSION-DATA:DATA-ID="CLUSTER",VALUE="tyo01" #EXT-X-SESSION-DATA:DATA-ID="ABS",VALUE="false" #EXT-X-SESSION-DATA:DATA-ID="VIDEO-SESSION-ID",VALUE="[19桁の数字]" #EXT-X-SESSION-DATA:DATA-ID="BROADCAST-ID",VALUE="[11桁の数字]" #EXT-X-SESSION-DATA:DATA-ID="STREAM-TIME",VALUE="247.676031" #EXT-X-SESSION-DATA:DATA-ID="FUTURE",VALUE="true" #EXT-X-SESSION-DATA:DATA-ID="MANIFEST-CLUSTER",VALUE="tyo01" #EXT-X-SESSION-DATA:DATA-ID="ORIGIN",VALUE="sjc02" #EXT-X-SESSION-DATA:DATA-ID="C",VALUE="[1000文字超のランダムな文字列]" #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="chunked",NAME="1080p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=5593120,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2",VIDEO="chunked",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列1].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="720p30",NAME="720p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=2341740,RESOLUTION=1280x720,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="720p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列2].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="480p30",NAME="480p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=1396740,RESOLUTION=852x480,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="480p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列3].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="360p30",NAME="360p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=630000,RESOLUTION=640x360,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="360p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列4].m3u8 #EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="160p30",NAME="160p",AUTOSELECT=YES,DEFAULT=YES #EXT-X-STREAM-INF:BANDWIDTH=230000,RESOLUTION=284x160,CODECS="avc1.4D401F,mp4a.40.2",VIDEO="160p30",FRAME-RATE=30.000 https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列5].m3u8
各ABRに対応するm3u8ファイルについては、アクセス時のtokenは付与されていないようです。実際にアクセスしてみます。以下のようにtoken情報がなくてもアクセス可能なようでした。
% curl -I https://video-weaver.tyo01.hls.live-video.net/v1/playlist/[800文字超のランダムな文字列1].m3u8 HTTP/1.1 200 OK Access-Control-Allow-Origin: * Cache-Control: no-cache, no-store, private Content-Type: application/vnd.apple.mpegurl Vary: Accept-Encoding Date: Wed, 30 Sep 2020 06:26:17 GMT
Access-Control-Allow-Originヘッダについてもドメインの指定はない状態です。さらに各ABRのm3u8、その一つの中身からtsファイルのヘッダ情報も確認してみます。m3u8の中身は先ほど例示したものと大差なさそうですので割愛します。
% curl -I https://video-edge-5cbaa4.tyo01.hls.live-video.net/v1/segment/[900文字超のランダムな文字列].ts HTTP/1.1 200 OK Accept-Ranges: bytes Access-Control-Allow-Origin: * Content-Length: 0 Content-Type: application/octet-stream Date: Wed, 30 Sep 2020 06:26:55 GMT
こちらもtokenを付与しなくてもコード200のレスポンスが返り、Access-Control-Allow-Originヘッダはすべてのドメインを対象にしていました。
これら、つまりPlayback URLから先のリクエストについては、tokenが不要であることならびにAccess-Control-Allow-Originヘッダの内容が変わることは、念のため気に留めておく必要があるかと思います。とは言え、1000文字近いランダムな文字列で構成されているので、第三者が推測してアクセスするなどは難しいかなと思います。
各ファイルごとのリクエスト先DNS名について
トップレベルマニフェストファイル、各ABRごとのマニフェストファイル、セグメントファイルのリクエスト先DNS名がそれぞれ異なっている、という事象がありました。これについて少し振り返っておきます。
まずトップレベルマニフェストファイル、つまりPlayback URLで払い出されるのは以下のドメインです。
XXXXXXXXXXXX.us-west-2.playback.live-video.net
はじめの文字列はランダム(おそらくAWSアカウント内、かつ同じリージョンのChannelでは同一のようでしたが)、続いてリージョン情報、そしてplayback.live-video.net
が続きます。
続いて、各ABRごとのマニフェストファイルのリクエスト先のドメインです。
video-weaver.tyo01.hls.live-video.net
そしてセグメントファイル(tsファイル)のリクエスト先ドメインは下記でした。
video-edge-7568a4.tyo01.hls.live-video.net
セグメントファイルのリクエスト応答は、エッジに分散させてリクエストを捌いているのでは?という推測ができますね。ところでtyo01
の部分、気なりませんか?MANIFEST-NODE
やMANIFEST-CLUSTER
でもtyo01
の文字列がありました。なんとなくですが、tyoがtokyoを表しているのかな?な気もします。(空港コードでは東京地区はTYOですよね。)
アクセス元によって変わる情報なのかな?という推測のもと、試しに東京リージョンに起動したEC2と、バージニアリージョンで起動したEC2で確認してみました。ドメインのみ抜粋した結果が以下です。
- 東京リージョンに起動したEC2からのリクエスト
- ABRごとのマニフェストファイルのドメイン
video-weaver.sin01.hls.live-video.net
- セグメントファイルのドメイン
video-edge-c68324.sin01.hls.live-video.net
- ABRごとのマニフェストファイルのドメイン
- バージニアリージョンに起動したEC2からのリクエスト
- ABRごとのマニフェストファイルのドメイン
video-weaver.sea01.hls.live-video.net
- セグメントファイルのドメイン
video-edge-8c7934.iad05.hls.live-video.net
- ABRごとのマニフェストファイルのドメイン
東京リージョンでtyo
となれば推測通りかなと思ったのですが、sin
でした。けどこれは、空港コードでシンガポールに該当します。(シンガポール・チャンギ国際空港 - Wikipedia)AWSも東京リージョンがまだない時はシンガポールリージョンを使うことも多かっただろうし、「ドメイン名の一部はアクセス元によって変わる、そのドメイン名には空港コードが使われている」という予想はいい線いっているのでは?ないでしょうか。
続いてバージニアリージョンからのリクエストです、こちらはseaとiad、空港コードで検索すると前者はシアトル・タコマ国際空港、後者はワシントン・ダレス国際空港に該当します。ワシントンは東海岸なので、バージニアに近いと言えると思います。対してシアトルは西海岸です。IVSのリソースがオレゴンにあることも影響しているのでしょうか。はたまた、ドメイン名が地理的な情報を表している、という推測が勘違いなのか……。
なお、Amazon IVSが動画を扱うソリューションということで、Amazon CloudFrontなどCDNとの連携を思いつくこともあるかと思います。そもそもAmazon IVSには専用のCDNが内包されているとのことでCDN連携をさせる必要はないと思うのですが、仮に連携を検討した場合、上記のようなリソースの違い、そして(おそらく)地理的条件によりDNS名が変わる、という点は考慮すべき点かと思います。(そしておそらく、「連携は難しい」という判断にならざるを得ないかとも思います。)
ライブ配信をしていないときのマニフェストファイル
ライブ配信をしていないとき(今回は映像を打ち上げておらず、IVS ChannelのStatusがOfflineのとき)のマニフェストファイルについても確認してみたのでまとめておきます。
まずはレスポンスヘッダの内容です。
% curl -I https://XXXXXXXXXXXX.us-west-2.playback.live-video.net/api/video/v1/us-west-2.123456789012.channel.XXXXXXXXsS0f.m3u8 HTTP/1.1 404 Not Found Server: nginx/1.14.1 Date: Tue, 29 Sep 2020 10:39:45 GMT Content-Type: application/json Content-Length: 187 Access-Control-Allow-Origin: * Cache-Control: no-cache,no-store
ステータスコードとして404
が返ってきていることがわかります。続いて実際のレスポンスの内容です。
% curl https://XXXXXXXXXXXX.us-west-2.playback.live-video.net/api/video/v1/us-west-2.123456789012.channel.XXXXXXXXsS0f.m3u8 [{"url":"/api/video/v1/us-west-2.123456789012.channel.XXXXXXXXsS0f.m3u8","error":"twirp error not_found: transcode does not exist","error_code":"transcode_does_not_exist","type":"error"}]%
トランスコードが存在しない(変換された映像がない)旨のエラーが返ります。(親切ですね!)
上記はいちどライブストリーミングを実施したチャンネルで停止した際に確認したのですが、Channel作成後いちどもライブストリーミングを行っていない(映像を打ち上げていない)Channelだと以下のようなエラーレスポンスが返ってきました。
% curl -I https://XXXXXXXXXXXX.us-west-2.playback.live-video.net/api/video/v1/us-west-2.123456789012.channel.TcYtHKkEO65t.m3u8 HTTP/1.1 404 Not Found Server: nginx/1.14.1 Date: Tue, 29 Sep 2020 10:45:00 GMT Content-Type: text/plain; charset=utf-8 Content-Length: 21 X-Content-Type-Options: nosniff Cache-Control: no-cache,no-store % curl https://XXXXXXXXXXXX.us-west-2.playback.live-video.net/api/video/v1/us-west-2.123456789012.channel.TcYtHKkEO65t.m3u8 Can not find channel
Can not find channel
、Channelの使用状況でエラー内容が変わるのは少し興味深いですね。
Playback URLについて
最後に、Playback URL自体についても少し確認してみます。
live-video.netドメイン
Playback URLは以下の形式で払い出されますね。
https://XXXXXXXXXXXX.us-west-2.playback.live-video.net/api/video/v1/us-west-2.123456789012.channel.XXXXXXXX6CFp.m3u8
各ファイルごとのDNS名についても先ほど確認しましたが、ドメインとしては一貫してlive-video.net
を使っているようです。ぱっと見AWSっぽくない(AWSやAmazonなどの文字列が含まれていない)、としながらもライブストリーミングソリューションにはぴったりのドメイン名だなと個人的には思いました。
ちなみに、一般固有名詞なドメインということから、すでに歴史があるようで?Internet ArchiveのWayback Machineで調べてみると、2017年時点では以下のようなロシア語、ブライダル関連と思われるサイトだったようです。この会社?が現在のAmazon IVSに繋がるのか、たまたま取得できたドメインをAWSが使っているのかは定かではありません。(個人的な印象としては後者なのかな?と思っていますが。)ちなみに2000年代もまた別の用途でドメインが使われていたようで(ドメインの所有者が別だったのでしょうか)、こちらはむやみに確認しないことをおすすめします。
Playback URLにAWSアカウントID
Playback URLドメイン名に続いて、パス部分にも注目してみます。
/api/video/v1/us-west-2.123456789012.channel.XXXXXXXX6CFp.m3u8
マニフェストファイル(m3u8ファイル)のファイル名、先頭にリージョン名がきて、続くのは12桁の数字ですね。この数字、確認してみるとAWSアカウントIDと一致していました。AWSアカウントIDについては、それを公開することで直接的な実害はないかと思いますが(他にも事情によりAWSアカウントIDを公開するという場面はいくつかあるかと思います)、例えばIAMユーザのAWSマネジメントコンソールへのログインの際の情報の一つであり、可能であれば秘匿したい情報かと考えます。リソース識別に使われる情報でもあり(ARNなど)、攻撃の手がかりになってしまう可能性もあります。もしこれらの点が気になるようであれば、Amazon IVS利用の際、専用のAWSアカウントの準備することも一つの手段かと思いました。
まとめ
ということで、Amazon IVSのマニフェストファイルを眺めながら、サーバ情報やABR情報、そしてCORS設定やアクセス先DNS名などについて確認してみました。なお今回確認した項目のうち、仕様やドキュメントなどに記載がない項目については、今後変更される可能性もあるのかなと思います。あくまで2020年9月の時点での情報であることにご留意ください。(例えばヘッダ情報で確認できたServer: nginx/1.14.1
、同様の記載が確認できるAWS Elemental MediaPackageではServer: AWS Elemental MediaPackage
という情報が確認できた時期もありました。)
脚注
Amazon Interactive Video Service では、取り込んだ RTMPS の品質と解像度に基づき、出力トランスコードのための異なる適応ビットレート(ABR)セットを生成します。最高で 8.5Mbps、1080p60 のストリームを送信した場合、Amazon IVS は、8.5Mbps 1080p60、3Mbps 720p60、2Mbps 720p30、1.2Mbps 480p30、800Kbps 360p30、400Kbps 160p30 の各レンディションを 1 つの ABR ストリームの中に作成します。
Amazon Interactive Video Service のよくある質問(2020/09/30) ↩